


#include "agent.h"
#include "state.h"
#include "header.h"


#include <kernel/userid/userid.h>


/* Create an agent up from nothing but bytecode!
 * The agent's name is read from the header.  We can use this name to 
 * figure out everything else via handle name resolution. */
extern vm_Agent *vm_agent_request (handle _bytestream, userid _id)
{
	vm_Agent *agent;

	agent = (vm_Agent *) block_request (sizeof (vm_Agent));

	handle_read (_bytestream, (char *) &agent->Header, sizeof (vm_Header));

	/* the agent has a unique ID and belongs to the host's group */
	agent->ID = userid_request ();
	userid_join (agent->ID, _id);

	agent->ByteStream = _bytestream;
	agent->WaitQueue = handle_request (agent->Header.HostName, _id);
	agent->InputStream = handle_request (agent->Header.AgentName, agent->ID);
	agent->Status = VM_AGENT_SLEEPING;
	agent->ReferenceCount = 0;

	return agent;
}


extern void vm_agent_release (vm_Agent *_agent)
{
	handle_release (_agent->WaitQueue);
	handle_release (_agent->InputStream);
	
	if (_agent->Status == VM_AGENT_AWAKE)
	{
		block_release (_agent->ByteCache);
	}

	block_release (_agent);
}


extern int vm_agent_wake (vm_Agent *_agent)
{
	switch (_agent->Status)
	{
	case VM_AGENT_AWAKE :
	
		return 0;

	case VM_AGENT_DEAD :
		
		return -1;
	}

	handle_read (_agent->ByteStream, (char *) &_agent->Header, sizeof (vm_Header));

	_agent->ByteCacheSize = _agent->Header.TextSegmentSize + _agent->Header.DataSegmentSize + _agent->Header.CodeSegmentSize;
	_agent->ByteCache = (char *) block_request (_agent->ByteCacheSize);

	handle_read (_agent->ByteStream, _agent->ByteCache, _agent->ByteCacheSize);

	_agent->TextSegment = _agent->ByteCache;
	_agent->DataSegment = (vm_Datum *) _agent->TextSegment + _agent->Header.TextSegmentSize;
	_agent->CodeSegment = (int *) _agent->DataSegment + _agent->Header.DataSegmentSize;

	_agent->Status = VM_AGENT_AWAKE;
	
	return 0;
}


extern int vm_agent_sleep (vm_Agent *_agent)
{
	switch (_agent->Status)
	{
	case VM_AGENT_SLEEPING :
		
		return 0;

	case VM_AGENT_DEAD :
		
		return -1;
	}

	handle_write (_agent->ByteStream, (char *) &_agent->Header, sizeof (vm_Header));
	handle_write (_agent->ByteStream, _agent->ByteCache, _agent->ByteCacheSize);

	block_release (_agent->ByteCache);

	_agent->Status = VM_AGENT_SLEEPING;

	return;
}

